package jef.tools.reflect;

import java.lang.reflect.Field;

import jef.tools.Assert;
import sun.misc.Unsafe;

/**
 * 使用sun.misc.Unsafe进行一些特殊操作的工具类
 * 
 * @author jiyi
 *
 */
@SuppressWarnings("restriction")
public final class UnsafeUtils {
	
	static sun.misc.Unsafe unsafe;
	public static long stringoffset;
	public static boolean enable=System.getProperty("disable.unsafe")==null;
	
	static {
		try {
			Class<?> clazz = Class.forName("sun.misc.Unsafe");
			Field field = clazz.getDeclaredField("theUnsafe");
			field.setAccessible(true);
			unsafe = (Unsafe) field.get(null);
			java.lang.reflect.Field stringValue=String.class.getDeclaredField("value");
			stringoffset=unsafe.objectFieldOffset(stringValue);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	
	/**
	 * 获取Unsafe对象
	 * @return
	 */
	public final static sun.misc.Unsafe getUnsafe(){
		return unsafe;
	}
	
	/**
	 * 不使用反射直接创造对象，注意类的构造方法不会被执行
	 * @param clz
	 * @return 被构造的对象
	 */
	@SuppressWarnings("unchecked")
	public final static <T> T newInstance(Class<T> clz){
		try {
			return (T) unsafe.allocateInstance(clz);
		} catch (InstantiationException e) {
			throw new IllegalStateException(e.getCause());
		}
	}
	

	/**
	 * 用指定的ClassLoader加载二进制数据为class
	 * @param className
	 * @param data
	 * @param i
	 * @param length
	 * @param classLoader
	 * @return
	 */
	public final static Class<?> defineClass(String className, byte[] data, int i, int length, ClassLoader classLoader) {
		if(data==null || data.length==0){
			throw new IllegalArgumentException("the input class data is empty!");
		}
		if(length<1 || i+length<data.length){
			throw new IllegalArgumentException("the input length is invalid!");
		}
		if(className==null || className.length()==0){
			throw new IllegalArgumentException("the class name is invalid!"+className);
		}
		Assert.notNull(classLoader);
//		LogUtil.debug("Unsafe load class ["+className+"] to "+classLoader);
		return unsafe.defineClass(className, data, i, length, classLoader, null);
	}
	
	/**
	 * 返回String对象中的char[]数组。<br>
	 * 修改String 中的char[]是十分危险的，尤其是当被修改的char[]是属于常量池的String时，会发生十分难以检测的，不可预期的问题。
	 * <p>
	 * 因此这个方法用来：
	 * 1、获取String中的char[]，用于读取和遍历。
	 * 2、只有当非常确信String所引用的char[]不在常量池中时，可以进行修改。如果一个常量string进行substring操作，会产生的一个不完全对象的String。
	 * 这个string的char[]引用上一个string的char[]，因此只有确信string对象是通过拼接等方式重新生成时，才能使用此方法
	 * 
	 * <p>
	 * 这个方法的意义所在：
	 * string.toCharArray();方法和这个很相似，但是性能上要稍微差一点。这个差别非常小。
	 * 以长度为8的string来测试，运行一万次，toCharArray耗时3000us(当string比较大时可能更慢)，调用这个方法耗时约1000us(由于不用创建新对象)。
	 * <p>
	 * 实际测试发现，通过toCharArray来遍历对象要比下面的方法更耗时。
	 * 	for(int j=0;j<s.length();j++){
	 *		char c=s.charAt(j);
	 *	}
	 * 而这种方式和unsafe的方式其实耗时差距不大。
	 * 
	 * @param str
	 * @return
	 */
	public final static char[] getValue(String str){
		return (char[])unsafe.getObject(str, stringoffset);
	}
}
